package lock;

import java.util.List;
import java.util.Map;
import java.util.Set;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * Redis 工具类：单例模式
 */
public class Redis {

	private volatile static Redis instance;

	private static JedisPool jedisPool;

	private Redis() {}

	
	public void init(JedisPool jedisPool)
	{
		this.jedisPool= jedisPool;
	}
	
	public static Redis getInstance() {
		if (instance == null) {
			synchronized (Redis.class) {
				if (instance == null) {
					instance = new Redis();
				}
			}
		}
		return instance;
	}

	public JedisPool getJedisPool() {
		return jedisPool;
	}

	public Jedis getJedis() {
		return jedisPool.getResource();
	}

	public void close(Jedis jedis) {
		if (jedis != null) {
			jedis.close();
			// jedisPool.returnResource(jedis);
		}
	}

	/**
	 * 在redis中执行
	 * @param callback
	 * @return
	 * @throws Exception 
	 */
	public <T> T execute(RedisCallback<T> callback) throws Exception {
		Jedis jedis = getJedis();
		try {
			return (T) callback.call(jedis);
		}finally {
			close(jedis);
		}
	}

	/**
	 * 返回 key 所关联的 value 值 如果 key 不存在那么返回 null
	 */
	public String get(String key) {
		Jedis jedis = getJedis();
		try {
			return jedis.get(key);
		} finally {
			close(jedis);
		}
	}

	/**
	 * 存放 key value 对到 redis 如果 key 已经持有其他值， SET 就覆写旧值，无视类型。
	 */
	public String set(String key, String value) {
		Jedis jedis = getJedis();
		try {
			return jedis.set(key, value);
		} finally {
			close(jedis);
		}
	}

	/**
	 * SET if Not eXists：如果不存在，则 SET
	 * 
	 * @return 1 成功；0 失败
	 */
	public Long setnx(String key, String value) {
		Jedis jedis = getJedis();
		try {
			return jedis.setnx(key, value);
		} finally {
			close(jedis);
		}
	}

	/**
	 * 设置 key-value 对，并将 key 的生存时间设为 seconds (以秒为单位)。 如果 key 已经存在， SETEX
	 * 命令将覆写旧值。
	 */
	public String setex(String key, int seconds, String value) {
		Jedis jedis = getJedis();
		try {
			return jedis.setex(key, seconds, value);
		} finally {
			close(jedis);
		}
	}

	/**
	 * 为给定 key 设置生存时间，当 key 过期时(生存时间为 0 )，它会被自动删除
	 * 
	 * @return 1 成功；0 失败
	 */
	public Long expire(String key, int seconds) {
		Jedis jedis = getJedis();
		try {
			return jedis.expire(key, seconds);
		} finally {
			close(jedis);
		}
	}

	/**
	 * 以秒为单位，返回给定 key 的剩余生存时间(TTL, time to live)
	 * 
	 * @return -2 key 不存在；-1 key 存在但没有设置ttl；key 的剩余生存时间
	 */
	public Long ttl(String key) {
		Jedis jedis = getJedis();
		try {
			return jedis.ttl(key);
		} finally {
			close(jedis);
		}
	}

	/**
	 * 将给定 key 的值设为 value ，并返回 key 的旧值(old value)。 当 key 存在但不是字符串类型时，返回一个错误。
	 */
	public String getSet(String key, String value) {
		Jedis jedis = getJedis();
		try {
			return jedis.getSet(key, value);
		} finally {
			close(jedis);
		}
	}

	/**
	 * 删除给定的一个 key，不存在的 key 会被忽略
	 */
	public Long del(String key) {
		Jedis jedis = getJedis();
		try {
			return jedis.del(key);
		} finally {
			close(jedis);
		}
	}

	/**
	 * 删除给定的多个 key，不存在的 key 会被忽略
	 */
	public Long del(String... keys) {
		Jedis jedis = getJedis();
		try {
			return jedis.del(keys);
		} finally {
			close(jedis);
		}
	}

	/**
	 * 查找所有符合给定模式 pattern 的 key 列表
	 */
	public Set<String> keys(String pattern) {
		Jedis jedis = getJedis();
		try {
			return jedis.keys(pattern);
		} finally {
			close(jedis);
		}
	}


	/**
	 * 将 key 中储存的数字值减一
	 */
	public Long decr(String key) {
		Jedis jedis = getJedis();
		try {
			return jedis.decr(key);
		} finally {
			close(jedis);
		}
	}

	/**
	 * 将 key 所储存的值减去减量 decrement
	 */
	public Long decrBy(String key, long longValue) {
		Jedis jedis = getJedis();
		try {
			return jedis.decrBy(key, longValue);
		} finally {
			close(jedis);
		}
	}

	/**
	 * 将 key 中储存的数字值增一
	 */
	public Long incr(String key) {
		Jedis jedis = getJedis();
		try {
			return jedis.incr(key);
		} finally {
			close(jedis);
		}
	}

	/**
	 * 将 key 所储存的值加上增量 increment
	 */
	public Long incrBy(String key, long longValue) {
		Jedis jedis = getJedis();
		try {
			return jedis.incrBy(key, longValue);
		} finally {
			close(jedis);
		}
	}

	/**
	 * 检查给定 key 是否存在
	 */
	public boolean exists(String key) {
		Jedis jedis = getJedis();
		try {
			return jedis.exists(key);
		} finally {
			close(jedis);
		}
	}

	/**
	 * 将一个或多个值 value 插入到列表 key 的表头。如果有多个 value 值，那么各个 value 值按从左到右的顺序依次插入到表头：
	 * 比如说， 对空列表 mylist 执行命令 LPUSH mylist a b c ，列表的值将是 c b a ， 这等同于原子性地执行 LPUSH
	 * mylist a 、 LPUSH mylist b 和 LPUSH mylist c 三个命令。 如果 key 不存在，一个空列表会被创建并执行
	 * LPUSH 操作。 当 key 存在但不是列表类型时，返回一个错误。
	 */
	public Long lpush(String key, String... values) {
		Jedis jedis = getJedis();
		try {
			return jedis.lpush(key, values);
		} finally {
			close(jedis);
		}
	}

	/**
	 * 移除并返回列表 key 的头元素。
	 */
	public String lpop(String key) {
		Jedis jedis = getJedis();
		try {
			return jedis.lpop(key);
		} finally {
			close(jedis);
		}
	}

	/**
	 * 将一个或多个值 value 插入到列表 key 的表尾(最右边)。 如果有多个 value 值，那么各个 value
	 * 值按从左到右的顺序依次插入到表尾：比如 对一个空列表 mylist 执行 RPUSH mylist a b c ，得出的结果列表为 a b c ，
	 * 等同于执行命令 RPUSH mylist a 、 RPUSH mylist b 、 RPUSH mylist c 。 如果 key
	 * 不存在，一个空列表会被创建并执行 RPUSH 操作。 当 key 存在但不是列表类型时，返回一个错误。
	 */
	public Long rpush(String key, String... values) {
		Jedis jedis = getJedis();
		try {
			return jedis.rpush(key, values);
		} finally {
			close(jedis);
		}
	}

	/**
	 * 移除并返回列表 key 的尾元素。
	 */
	public String rpop(String key) {
		Jedis jedis = getJedis();
		try {
			return jedis.rpop(key);
		} finally {
			close(jedis);
		}
	}

	/**
	 * 返回列表 key 的长度。 如果 key 不存在，则 key 被解释为一个空列表，返回 0 . 如果 key 不是列表类型，返回一个错误。
	 */
	public Long llen(String key) {
		Jedis jedis = getJedis();
		try {
			return jedis.llen(key);
		} finally {
			close(jedis);
		}
	}

	/**
	 * 返回列表 key 中指定区间内的元素，区间以偏移量 start 和 stop 指定。 下标(index)参数 start 和 stop 都以 0
	 * 为底，也就是说，以 0 表示列表的第一个元素，以 1 表示列表的第二个元素，以此类推。 你也可以使用负数下标，以 -1 表示列表的最后一个元素，
	 * -2 表示列表的倒数第二个元素，以此类推。
	 * 
	 * <pre>
	 * 例子：
	 * 获取 list 中所有数据：cache.lrange(listKey, 0, -1);
	 * 获取 list 中下标 1 到 3 的数据： cache.lrange(listKey, 1, 3);
	 * </pre>
	 */
	public List<String> lrange(String key, long start, long end) {
		Jedis jedis = getJedis();
		try {
			List<String> data = jedis.lrange(key, start, end);
			return data;
		} finally {
			close(jedis);
		}
	}

	/**
	 * 返回列表 key 中，下标为 index 的元素。 下标(index)参数 start 和 stop 都以 0 为底，也就是说，以 0
	 * 表示列表的第一个元素， 以 1 表示列表的第二个元素，以此类推。 你也可以使用负数下标，以 -1 表示列表的最后一个元素， -2
	 * 表示列表的倒数第二个元素，以此类推。 如果 key 不是列表类型，返回一个错误。
	 */
	public String lindex(String key, long index) {
		Jedis jedis = getJedis();
		try {
			return jedis.lindex(key, index);
		} finally {
			close(jedis);
		}
	}
	
	/**
	 * 将哈希表 key 中的域 field 的值设为 value 。
	 * 如果 key 不存在，一个新的哈希表被创建并进行 HSET 操作。
	 * 如果域 field 已经存在于哈希表中，旧值将被覆盖。
	 */
	public Long hset(String key, String field, String value) {
		Jedis jedis = getJedis();
		try {
			return jedis.hset(key, field, value);
		} finally {
			close(jedis);
		}
	}
	
	/**
	 * 同时将多个 field-value (域-值)对设置到哈希表 key 中。
	 * 此命令会覆盖哈希表中已存在的域。
	 * 如果 key 不存在，一个空哈希表被创建并执行 HMSET 操作。
	 */
	public String hmset(String key, Map<String, String> hash) {
		Jedis jedis = getJedis();
		try {
			return jedis.hmset(key, hash);
		} finally {
			close(jedis);
		}
	}
	
	/**
	 * 返回哈希表 key 中给定域 field 的值。
	 */
	public String hget(String key, String field) {
		Jedis jedis = getJedis();
		try {
			return jedis.hget(key, field);
		} finally {
			close(jedis);
		}
	}
	
	/**
	 * 返回哈希表 key 中，一个或多个给定域的值。
	 * 如果给定的域不存在于哈希表，那么返回一个 nil 值。
	 * 因为不存在的 key 被当作一个空哈希表来处理，所以对一个不存在的 key 进行 HMGET 操作将返回一个只带有 nil 值的表。
	 */
	public List<String> hmget(String key, String... fields) {
		Jedis jedis = getJedis();
		try {
			return jedis.hmget(key, fields);
		} finally {
			close(jedis);
		}
	}
	
	/**
	 * 删除哈希表 key 中的一个或多个指定域，不存在的域将被忽略。
	 */
	public Long hdel(String key, String... fields) {
		Jedis jedis = getJedis();
		try {
			return jedis.hdel(key, fields);
		} finally {
			close(jedis);
		}
	}
	
	/**
	 * 查看哈希表 key 中，给定域 field 是否存在。
	 */
	public boolean hexists(String key, String field) {
		Jedis jedis = getJedis();
		try {
			return jedis.hexists(key, field);
		}
		finally {close(jedis);}
	}
	
	/**
	 * 返回哈希表 key 中，所有的域和值。
	 * 在返回值里，紧跟每个域名(field name)之后是域的值(value)，所以返回值的长度是哈希表大小的两倍。
	 */
	public Map<String, String> hgetAll(String key) {
		Jedis jedis = getJedis();
		try {
			return jedis.hgetAll(key);
		} finally {
			close(jedis);
		}
	}
	
	/**
	 * 返回哈希表 key 中所有域的值。
	 */
	public List<String> hvals(String key) {
		Jedis jedis = getJedis();
		try {
			return jedis.hvals(key);
		} finally {
			close(jedis);
		}
	}
	
	/**
	 * 返回哈希表 key 中的所有域。
	 * 底层实现此方法取名为 hfields 更为合适，在此仅为与底层保持一致
	 */
	public Set<String> hkeys(String key) {
		Jedis jedis = getJedis();
		try {
			return jedis.hkeys(key);
		} finally {
			close(jedis);
		}
	}
	
	/**
	 * 返回哈希表 key 中域的数量。 
	 */
	public Long hlen(String key) {
		Jedis jedis = getJedis();
		try {
			return jedis.hlen(key);
		} finally {
			close(jedis);
		}
	}
	
	/**
	 * 为哈希表 key 中的域 field 的值加上增量 increment 。
	 * 增量也可以为负数，相当于对给定域进行减法操作。
	 * 如果 key 不存在，一个新的哈希表被创建并执行 HINCRBY 命令。
	 * 如果域 field 不存在，那么在执行命令前，域的值被初始化为 0 。
	 * 对一个储存字符串值的域 field 执行 HINCRBY 命令将造成一个错误。
	 * 本操作的值被限制在 64 位(bit)有符号数字表示之内。
	 */
	public Long hincrBy(String key, String field, long value) {
		Jedis jedis = getJedis();
		try {
			return jedis.hincrBy(key, field, value);
		} finally {
			close(jedis);
		}
	}

}
